# partially based on django-tremenus code written by Julien Phalip
# (http://code.google.com/p/django-treemenus/)
#
# Copyright (c) 2008, Julien Phalip
# Copyright (c) 2008-2009, Maxim Oransky
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#     * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import re
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.util import unquote
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import get_object_or_404
from django.utils.encoding import force_unicode
from django.utils.functional import wraps
from django.utils.html import escape
from django.utils.translation import ugettext as _
from djwheel.adminutils import create_advanced_admin_form, AdvancedAdmin
from utils import get_parent_choices, MenuItemChoiceField, move_item_or_clean_order
import models


class MenuItemAdmin(admin.ModelAdmin):
    ''' This class is used as a proxy by MenuAdmin to manipulate menu items.
    It should never be registered. '''
    form = create_advanced_admin_form(models.MenuItem)

    def __init__(self, model, admin_site, menu):
        #TODO: Try to get rid of _menu attribute...
        super(MenuItemAdmin, self).__init__(model, admin_site)
        self._menu = menu

    def delete_view(self, request, object_id, extra_context=None):
        if request.method == 'POST':
            # Delete and return to menu page
            ignored_response = super(MenuItemAdmin, self).delete_view(request, object_id, extra_context)
            return HttpResponseRedirect("../../../")
        else:
            # Show confirmation page
            return super(MenuItemAdmin, self).delete_view(request, object_id, extra_context)

    def save_model(self, request, obj, form, change):
        obj.menu = self._menu
        obj.save()

    def save_add(self, request, form, formsets, post_url_continue):
        response = super(MenuItemAdmin, self).save_add(request, form, formsets, post_url_continue)
        if '_continue' in request.POST:
            return response
        elif '_addanother' in request.POST:
            return HttpResponseRedirect(request.path)
        elif '_popup' in request.POST:
            return response
        else:
            return HttpResponseRedirect("../../")

    def save_change(self, request, form, formsets=None):
        response =  super(MenuItemAdmin, self).save_change(request, form, formsets)
        if '_continue' in request.POST:
            return HttpResponseRedirect(request.path)
        elif '_addanother' in request.POST:
            return HttpResponseRedirect("../add/")
        elif '_saveasnew' in request.POST:
            #TODO: Know issue: how to redirect to the newly created object's edit page?
            return HttpResponseRedirect("../../")
        else:
            return HttpResponseRedirect("../../")

    def get_form(self, request, obj=None, **kwargs):
        form = super(MenuItemAdmin, self).get_form(request, obj, **kwargs)
        choices = get_parent_choices(self._menu, obj)
        form.base_fields['parent'] = MenuItemChoiceField(choices=choices)
        def clean_named_url(self):
            from django.core.urlresolvers import reverse
            from django import forms
            named_url = self.cleaned_data['named_url']
            if named_url:
                try:
                    reverse(named_url)
                except Exception, e:
                    print e
                    raise forms.ValidationError(_("Page named %s does not exists.") % named_url)
            return named_url
        form.clean_named_url = clean_named_url
        #print form
        return form


class MenuAdmin(admin.ModelAdmin):
    menu_item_admin_class = MenuItemAdmin

    def __call__(self, request, url):
        ''' Overriden to route extra URLs.'''

        if url:
            if url.endswith('items/add'):
                return self.add_menu_item(request, unquote(url[:-10]))
            if url.endswith('items'):
                return HttpResponseRedirect('../')
            match = re.match('^(?P<menu_pk>[-\w]+)/items/(?P<menu_item_pk>[-\w]+)$', url)
            if match:
                return self.edit_menu_item(request, match.group('menu_pk'), match.group('menu_item_pk'))
            match = re.match('^(?P<menu_pk>[-\w]+)/items/(?P<menu_item_pk>[-\w]+)/delete$', url)
            if match:
                return self.delete_menu_item(request, match.group('menu_pk'), match.group('menu_item_pk'))
            match = re.match('^(?P<menu_pk>[-\w]+)/items/(?P<menu_item_pk>[-\w]+)/move_up$', url)
            if match:
                return self.move_up_item(request, match.group('menu_pk'), match.group('menu_item_pk'))
            match = re.match('^(?P<menu_pk>[-\w]+)/items/(?P<menu_item_pk>[-\w]+)/move_down$', url)
            if match:
                return self.move_down_item(request, match.group('menu_pk'), match.group('menu_item_pk'))

        return super(MenuAdmin, self).__call__(request, url)

    def get_object_with_change_permissions(self, request, model, obj_pk):
        ''' Helper function that returns a menu/menuitem if it exists and if the user has the change permissions '''
        try:
            obj = model._default_manager.get(pk=obj_pk)
        except model.DoesNotExist:
            # Don't raise Http404 just yet, because we haven't checked
            # permissions yet. We don't want an unauthenticated user to be able
            # to determine whether a given object exists.
            obj = None
        if not self.has_change_permission(request, obj):
            raise PermissionDenied
        if obj is None:
            raise Http404('%s object with primary key %r does not exist.' % (model.__name__, escape(obj_pk)))
        return obj

    def add_menu_item(self, request, menu_pk):
        ''' Custom view '''
        menu = self.get_object_with_change_permissions(request, models.Menu, menu_pk)
        menuitem_admin = self.menu_item_admin_class(models.MenuItem, self.admin_site, menu)
        return menuitem_admin.add_view(request, extra_context={ 'menu': menu })

    def edit_menu_item(self, request, menu_pk, menu_item_pk):
        ''' Custom view '''
        menu = self.get_object_with_change_permissions(request, models.Menu, menu_pk)
        menu_item_admin = self.menu_item_admin_class(models.MenuItem, self.admin_site, menu)
        return menu_item_admin.change_view(request, menu_item_pk, extra_context={ 'menu': menu })

    def delete_menu_item(self, request, menu_pk, menu_item_pk):
        ''' Custom view '''
        menu = self.get_object_with_change_permissions(request, models.Menu, menu_pk)
        menu_item_admin = self.menu_item_admin_class(models.MenuItem, self.admin_site, menu)
        return menu_item_admin.delete_view(request, menu_item_pk, extra_context={ 'menu': menu })

    def move_down_item(self, request, menu_pk, menu_item_pk):
        menu = self.get_object_with_change_permissions(request, models.Menu, menu_pk)
        menu_item = self.get_object_with_change_permissions(request, models.MenuItem, menu_item_pk)

        if menu_item.order < menu_item.siblings().count():
            move_item_or_clean_order(menu_item, 1)
            msg = _('The menu item "%s" was moved successfully.') % force_unicode(menu_item)
        else:
            msg = _('The menu item "%s" is not allowed to move down.') % force_unicode(menu_item)
        request.user.message_set.create(message=msg)
        return HttpResponseRedirect('../../../')

    def move_up_item(self, request, menu_pk, menu_item_pk):
        menu = self.get_object_with_change_permissions(request, models.Menu, menu_pk)
        menu_item = self.get_object_with_change_permissions(request, models.MenuItem, menu_item_pk)

        if menu_item.order > 0:
            move_item_or_clean_order(menu_item, -1)
            msg = _('The menu item "%s" was moved successfully.') % force_unicode(menu_item)
        else:
            msg = _('The menu item "%s" is not allowed to move up.') % force_unicode(menu_item)
        request.user.message_set.create(message=msg)
        return HttpResponseRedirect('../../../')

    list_display = (
        'name',
#        'lang',
        'description',
    )
    ordering = ('name',)
    list_display_links = (
        'name',
    )


class ContentInline(admin.StackedInline):
    model = models.Content
    form = create_advanced_admin_form(model,
        visual_editor=('content',) + getattr(models.Content, '_visual_editor', ()))
    max_num = 1
    fieldsets = [
        (_('Content'), {
            'fields': ('title', 'content')
        }),
        (_('SEO'), {
            'classes': ('collapse',),
            'fields': ('meta_keywords', 'meta_description')
        }),
    ]
    if hasattr(models, 'UserContent'):
        #print [f.name for f in models.UserContent._meta._fields() if hasattr(f, 'name')]
        fieldsets.insert(1,
            (None, {'fields': [f.name for f in models.UserContent._meta._fields() if hasattr(f, 'name')]} )
        )

class MenuItemWithContentAdmin(MenuItemAdmin):
    save_on_top = True
    inlines = (ContentInline,)

class MenuWithContentAdmin(MenuAdmin):
    menu_item_admin_class = MenuItemWithContentAdmin

#admin.site.register(Menu, MenuAdmin)
admin.site.register(models.Menu, MenuWithContentAdmin)


class FreeContentAdmin(AdvancedAdmin):
    model = models.FreeContent
    ordering = ('name',)
    list_display = ('name', 'description', 'adm_value',)
    list_display_links = ('adm_value', 'description',)
    visual_editor = ('value',)

class LegendAdmin(AdvancedAdmin):
    model = models.Legend
    ordering = ('name',)
    list_display = ('name', 'description', 'value',)
    list_display_links = ('value', 'description',)


class ImagesAdmin(AdvancedAdmin):
    model = models.Images
    ordering = ('-id',)
    list_display = (
        'description',
        'adm_preview_image',
        'adm_path',
        'adm_code',
    )
    list_display_links = (
        'description',
        'adm_preview_image',
    )
    list_per_page = 15

class FilesAdmin(AdvancedAdmin):
    model = models.Files
    ordering = ('-id',)
    list_display = (
        'description',
        'adm_code',
    )
    list_display_links = (
        'description',
    )
    list_per_page = 15
